package edu.tamu.cse.lenss.service;

import java.util.List;

import android.app.Service;
import android.content.Intent;
import android.location.Location;
import android.location.LocationManager;
import android.net.wifi.ScanResult;
import android.os.Binder;
import android.os.IBinder;
import android.telephony.NeighboringCellInfo;
import android.telephony.SignalStrength;
import android.telephony.cdma.CdmaCellLocation;
import android.telephony.gsm.GsmCellLocation;
import edu.tamu.cse.lenss.FileHandler;
import edu.tamu.cse.lenss.sensor.AccController;
import edu.tamu.cse.lenss.sensor.AccController.AccListener;
import edu.tamu.cse.lenss.sensor.CellTowerController;
import edu.tamu.cse.lenss.sensor.CellTowerController.CellTowerListener;
import edu.tamu.cse.lenss.sensor.LocationController;
import edu.tamu.cse.lenss.sensor.LocationController.LocationControllerListener;
import edu.tamu.cse.lenss.sensor.SensorInfo.SensorType;
import edu.tamu.cse.lenss.sensor.WiFiController;
import edu.tamu.cse.lenss.sensor.WiFiController.WifiControllerListener;
import edu.tamu.cse.lenss.utils.Logger;

public class SensorService extends Service {
	private static final String TAG = SensorService.class.getSimpleName();
	private final IBinder binder = new LocalBinder();
	private AccController accController;
	private LocationController gpsController;
	private LocationController networkLocationController;
	private CellTowerController cellTowerController;
	private WiFiController wifiController;
	private FileHandler lenssFile;
	
	public class LocalBinder extends Binder {
		public SensorService getService() {
			return SensorService.this;
		}
	}
	
	@Override
	public void onDestroy() {
		super.onDestroy();
		if(accController != null)
			accController.unregisterAcc();
		if(networkLocationController != null)
			networkLocationController.stopUpdateLocation();
		if(gpsController != null)
			gpsController.stopUpdateLocation();
		if(cellTowerController != null)
			cellTowerController.unregisterLocationUpdate();
		if(wifiController != null)
			wifiController.stopScan();
			
		Logger.v(TAG, "Service is destroied");
	}

	@Override
	public void onCreate() {
		super.onCreate();
		
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		// Check the system
		if(!initProcess()){
			stopSelfResult(startId);
			return START_NOT_STICKY;
		}
		else{
			// Start Accelerometer
			accController = new AccController(getBaseContext(), accListener);
			if(accController.init())
				accController.registerAcc(AccController.ACC_SENSITIVITY0);
			// Start Network Location
			networkLocationController = new LocationController(LocationController.LocationProvider.NETWORK, 
					3000,locationListener, getBaseContext());
			networkLocationController.startUpdateLocation();
			// Start GPS Location
			gpsController = new LocationController(LocationController.LocationProvider.GPS, 
					3000,locationListener, getBaseContext());
			gpsController.startUpdateLocation();
			// Start Cell Tower Observer
			cellTowerController = new CellTowerController(getBaseContext(), cellTowerListener);
			cellTowerController.registerLocationUpdate();
			// Start Wifi Scanner
			wifiController = new WiFiController(getBaseContext(), wifiListener);
			wifiController.startScan();
			
			lenssFile = new FileHandler(this);
			return START_STICKY;
		}
	}

	@Override
	public IBinder onBind(Intent intent) {
		return binder;
	}
	
	private AccListener accListener = new AccListener(){
		public void onNewValues(float[] values) {
			String data = System.currentTimeMillis() + ", " + values[0] + ", "
				+ values[1] + ", " + values[1] + "\n";
			lenssFile.appendSensorData(SensorType.ACCELEROMETER, data);
		}
	};
	
	private LocationControllerListener locationListener = new LocationControllerListener(){
		public void onNewUpdate(Location location) {
			String data = location.getTime() + ", " + location.getLongitude() + ", "
					+ location.getLatitude() + ", " + location.getAltitude() + ", "
					+ location.getBearing() + ", " + location.getSpeed() + ", "
					+ location.getAccuracy() + "\n";
			
			if(location.getProvider().equals(LocationManager.GPS_PROVIDER))
				lenssFile.appendSensorData(SensorType.GPS, data);
			else if(location.getProvider().equals(LocationManager.NETWORK_PROVIDER))
				lenssFile.appendSensorData(SensorType.NETWORK_LOC, data);
		}
		public void onError(String msg) {
		}
	};
	
	private CellTowerListener cellTowerListener = new CellTowerListener(){

		public void onGsmNewLocation(GsmCellLocation location,
			List<NeighboringCellInfo> neighbors, SignalStrength strength) {
			long time = System.currentTimeMillis();
			StringBuilder data = new StringBuilder();
			data.append(time + ", ");
			data.append(location.getCid() + ", " + location.getLac() + ", ");
			if(strength != null)
				data.append(strength.getGsmSignalStrength() + ", " + strength.getGsmBitErrorRate() + "\n");
			else
				data.append("\n");
			for(NeighboringCellInfo neighbor : neighbors){
				data.append(time + ", ");
				data.append(neighbor.getCid() + ", " + neighbor.getLac() + ", ");
				data.append(neighbor.getRssi() + "\n");
			}
			data.append("\n");
			lenssFile.appendSensorData(SensorType.GSM, data.toString());
		}

		public void onCdmaNewLocation(CdmaCellLocation location,
				SignalStrength strength) {
			StringBuilder data = new StringBuilder();
			data.append(System.currentTimeMillis() + ", ");
			data.append(location.getBaseStationId() + ", " + location.getBaseStationLatitude() + ", " + location.getBaseStationLongitude() + ", ");
			data.append(location.getNetworkId() + ", " + location.getSystemId() + ", ");
			if(strength != null)
				data.append(strength.getCdmaDbm() + ", " + strength.getCdmaEcio() + ", " + strength.getEvdoDbm() + ", " + strength.getEvdoEcio() + "\n");
			else
				data.append("\n");
			lenssFile.appendSensorData(SensorType.CDMA, data.toString());
		}
	};
	
	private WifiControllerListener wifiListener = new WifiControllerListener(){
		public void onStateChanged(List<ScanResult> results) {
			long time = System.currentTimeMillis();
			StringBuilder data = new StringBuilder();
			for(ScanResult result:results){
				//Logger.v(TAG, "SSID: " + result.SSID);
				data.append(time + ", " + result.SSID + ", ");
				data.append(result.BSSID + ", " + result.frequency + ", " + result.level + "\n");				
			}
			data.append("\n");
			lenssFile.appendSensorData(SensorType.WIFI, data.toString());			
		}
	};
	
	private boolean initProcess(){
		if(!FileHandler.isExternalStorageAvailable()){
			Logger.e(TAG, "SD Card is not available");
			return false;
		}
		if(!FileHandler.createRequiredFiles()){
			Logger.e(TAG, "Fail to create files");
			return false;
		}
		return true;
	}
}
